/********************************************************************************
 * @file    timer_scheduler.c
 * @brief   定时器调度器
 * 
 * @author  nzttj
 * @date    2025-04-02
 * @version 1.0
 * 
 * Copyright (C) 2025 nzttj
 * 
 * 本软件使用 GNU 通用公共许可证 (GPL) 第 3 版授权。
 * 
 * 您可以自由使用、修改、分发本软件，但必须遵守以下条件：
 * 1. 源代码必须开放，且您修改后的代码也必须以 GPL 许可证发布。
 * 2. 发布或分发本软件时，必须附带本许可证，并提供源代码或获取源代码的方式。
 * 
 * 本软件按"原样"提供，不附带任何担保，使用风险由用户自行承担。
 * 
 ********************************************************************************/

#include <string.h>
#include <time.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_timer.h"

#include "timer_scheduler.h"
#include "timer_storage.h"

/** @brief 调度器任务栈大小 */
#define SCHEDULER_STACK_SIZE 3072

/** @brief 调度器任务优先级 */
#define SCHEDULER_PRIORITY 5

/** @brief 定时器检查间隔(毫秒) */
#define CHECK_INTERVAL_MS 1000  // 1秒检查一次

/** @brief 定时器触发窗口(秒) */
#define TRIGGER_WINDOW_SEC 5  // 触发窗口5秒

static const char *TAG = "timer_scheduler";

/**
 * @brief 调度器任务上下文结构体
 */
typedef struct {
    TaskHandle_t task_handle;     ///< 任务句柄
    bool running;                 ///< 运行状态标志
    bool paused;                  ///< 暂停状态标志
    SemaphoreHandle_t mutex;      ///< 互斥锁，用于保护定时器列表
} scheduler_task_ctx_t;

/** @brief 调度器任务上下文实例 */
static scheduler_task_ctx_t s_task_ctx = {0};

/**
 * @brief 检查时间是否在指定范围内
 * 
 * @param timeinfo 当前时间信息
 * @param start_hour 起始小时
 * @param start_min 起始分钟
 * @param start_sec 起始秒
 * @param end_hour 结束小时
 * @param end_min 结束分钟
 * @param end_sec 结束秒
 * @return bool 是否在时间范围内
 */
static bool is_time_in_range(const struct tm *timeinfo, 
                           uint8_t start_hour, uint8_t start_min, uint8_t start_sec,
                           uint8_t end_hour, uint8_t end_min, uint8_t end_sec)
{
    if (!timeinfo) {
        ESP_LOGE(TAG, "Invalid timeinfo pointer");
        return false;
    }

    // 转换为秒数便于比较
    uint32_t current = timeinfo->tm_hour * 3600 + timeinfo->tm_min * 60 + timeinfo->tm_sec;
    uint32_t start = start_hour * 3600 + start_min * 60 + start_sec;
    uint32_t end = end_hour * 3600 + end_min * 60 + end_sec;

    // 如果结束时间小于开始时间,说明跨越了午夜
    if (end < start) {
        return (current >= start) || (current <= end);
    }
    
    return (current >= start) && (current <= end);
}

/**
 * @brief 检查定时器是否应该触发
 * 
 * @param timer 定时器配置
 * @return bool 是否应该触发
 */
static bool should_timer_trigger(timer_config_t *timer)
{
    if (!timer) {
        ESP_LOGE(TAG, "Invalid timer pointer");
        return false;
    }

    time_t now;
    struct tm timeinfo;
    if (time(&now) == -1) {
        ESP_LOGE(TAG, "Failed to get current time");
        return false;
    }
    if (!localtime_r(&now, &timeinfo)) {
        ESP_LOGE(TAG, "Failed to convert time");
        return false;
    }

    // 对于时间段模式,使用特殊的检查逻辑
    if (timer->type == TIMER_TYPE_PERIOD) {
        // 检查当天是否在day_mask中 (如果设置了day_mask)
        // 注意：timeinfo.tm_wday中，0=周日，1=周一，...，6=周六
        // day_mask的定义也是：第0位=周日，第6位=周六
        if (timer->time.day_mask != 0 && !(timer->time.day_mask & (1 << timeinfo.tm_wday))) {
            // 不在指定的日期内，如果当前在时间段内，需要触发离开事件
            if (timer->in_period) {
                ESP_LOGI(TAG, "Timer %d leaving period due to day change", timer->id);
                timer->in_period = false;
                return true;  // 触发结束动作
            }
            return false; // 当天不在day_mask指定的日期内，不触发
        }
        
        bool currently_in_period = is_time_in_range(&timeinfo,
            timer->time.hour, timer->time.minute, timer->time.second,
            timer->end_time.hour, timer->end_time.minute, timer->end_time.second);

        // 检测进入时间段
        if (!timer->in_period && currently_in_period) {
            ESP_LOGI(TAG, "Timer %d entering period", timer->id);
            timer->in_period = true;
            return true;  // 触发开始动作
        }
        // 检测离开时间段
        else if (timer->in_period && !currently_in_period) {
            ESP_LOGI(TAG, "Timer %d leaving period", timer->id);
            timer->in_period = false;
            return true;  // 触发结束动作
        }
        return false;
    }

    // 将当前时间和目标时间转换为秒数进行比较
    uint32_t current_seconds = timeinfo.tm_hour * 3600 + timeinfo.tm_min * 60 + timeinfo.tm_sec;
    uint32_t target_seconds = timer->time.hour * 3600 + timer->time.minute * 60 + timer->time.second;
    
    // 只在目标时间之后的TRIGGER_WINDOW_SEC秒内触发
    if (current_seconds < target_seconds || 
        current_seconds > target_seconds + TRIGGER_WINDOW_SEC) {
        return false;
    }

    // 检查是否在同一天内已经触发过
    struct tm last_trigger_tm;
    if (timer->last_trigger_time > 0) {
        localtime_r(&timer->last_trigger_time, &last_trigger_tm);
        // 如果是同一天且已经触发过，则不再触发
        if (timeinfo.tm_year == last_trigger_tm.tm_year &&
            timeinfo.tm_mon == last_trigger_tm.tm_mon &&
            timeinfo.tm_mday == last_trigger_tm.tm_mday) {
            return false;
        }
    }

    // 检查周期类型
    switch (timer->type) {
        case TIMER_TYPE_ONCE: {
            ESP_LOGI(TAG, "One-time timer %d triggered", timer->id);
            return true;
        }

        case TIMER_TYPE_DAILY:
            ESP_LOGI(TAG, "Daily timer %d triggered", timer->id);
            return true;

        case TIMER_TYPE_WEEKLY:
            // 已经按照 tm_wday 定义调整，0=周日，1=周一，...，6=周六
            if (timer->time.day_mask & (1 << timeinfo.tm_wday)) {
                ESP_LOGI(TAG, "Weekly timer %d triggered on day %d", timer->id, timeinfo.tm_wday);
                return true;
            }
            return false;

        default:
            ESP_LOGE(TAG, "Invalid timer type: %d", timer->type);
            return false;
    }
}

/**
 * @brief 调度器任务函数
 * 
 * 该任务负责定期检查和触发定时器。主要功能：
 * 1. 遍历所有启用的定时器
 * 2. 检查每个定时器是否应该触发
 * 3. 触发定时器回调
 * 4. 处理单次定时器的自动禁用
 * 
 * @param arg 调度器实例指针
 */
static void scheduler_task(void *arg)
{
    timer_scheduler_t *scheduler = (timer_scheduler_t *)arg;
    if (!scheduler) {
        ESP_LOGE(TAG, "Invalid scheduler pointer");
        vTaskDelete(NULL);
        return;
    }
    
    ESP_LOGI(TAG, "Scheduler task started");
    
    while (s_task_ctx.running) {
        // 如果处于暂停状态，等待恢复
        if (s_task_ctx.paused) {
            vTaskDelay(pdMS_TO_TICKS(CHECK_INTERVAL_MS));
            continue;
        }

        if (xSemaphoreTake(s_task_ctx.mutex, pdMS_TO_TICKS(100)) != pdTRUE) {
            ESP_LOGW(TAG, "Failed to take mutex, retrying...");
            continue;
        }

        // 遍历所有定时器
        for (int i = 0; i < scheduler->timer_count; i++) {
            timer_config_t *timer = &scheduler->timers[i];
            if (!timer->enabled) {
                continue;
            }

            if (!should_timer_trigger(timer)) {
                continue;
            }

            // 更新上次触发时间
            time(&timer->last_trigger_time);

            // 触发回调
            if (scheduler->callback_ctx.callback) {
                timer_action_t action = timer->action;
                
                // 对于时间段模式,根据当前是否在时间段内选择动作
                if (timer->type == TIMER_TYPE_PERIOD) {
                    action = timer->in_period ? timer->action : timer->end_action;
                }
                
                scheduler->callback_ctx.callback(
                    timer->id,
                    action,
                    scheduler->callback_ctx.user_data
                );
            }
            
            // 如果是单次定时器,触发后禁用
            if (timer->type == TIMER_TYPE_ONCE) {
                timer->enabled = false;
                nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
            }
        }

        xSemaphoreGive(s_task_ctx.mutex);
        vTaskDelay(pdMS_TO_TICKS(CHECK_INTERVAL_MS));
    }

    ESP_LOGI(TAG, "Scheduler task stopped");
    s_task_ctx.task_handle = NULL;
    vTaskDelete(NULL);
}

/**
 * @brief 初始化定时器调度器
 * 
 * @param scheduler 调度器实例
 * @param max_timers 最大定时器数量
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_init(timer_scheduler_t *scheduler, uint8_t max_timers)
{
    if (!scheduler || max_timers == 0) {
        return TIMER_ERR_INVALID_ARG;
    }

    if (s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_STATE;  // 已经初始化
    }

    // 创建互斥锁
    s_task_ctx.mutex = xSemaphoreCreateMutex();
    if (!s_task_ctx.mutex) {
        ESP_LOGE(TAG, "Failed to create mutex");
        return TIMER_ERR_NO_MEM;
    }

    // 分配定时器数组
    scheduler->timers = calloc(max_timers, sizeof(timer_config_t));
    if (!scheduler->timers) {
        ESP_LOGE(TAG, "Failed to allocate timer array");
        vSemaphoreDelete(s_task_ctx.mutex);
        s_task_ctx.mutex = NULL;
        return TIMER_ERR_NO_MEM;
    }

    scheduler->max_timers = max_timers;
    scheduler->timer_count = 0;
    memset(&scheduler->callback_ctx, 0, sizeof(timer_callback_ctx_t));

    ESP_LOGI(TAG, "Scheduler initialized with max %d timers", max_timers);
    return TIMER_OK;
}

/**
 * @brief 启动定时器调度器
 * 
 * @param scheduler 调度器实例
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_start(timer_scheduler_t *scheduler)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    if (s_task_ctx.running) {
        return TIMER_ERR_INVALID_STATE;
    }

    s_task_ctx.running = true;
    BaseType_t ret = xTaskCreate(
        scheduler_task,
        "timer_scheduler",
        SCHEDULER_STACK_SIZE,
        scheduler,
        SCHEDULER_PRIORITY,
        &s_task_ctx.task_handle
    );

    if (ret != pdPASS) {
        ESP_LOGE(TAG, "Failed to create scheduler task");
        s_task_ctx.running = false;
        return TIMER_ERR_TASK;
    }

    ESP_LOGI(TAG, "Scheduler started");
    return TIMER_OK;
}

/**
 * @brief 停止定时器调度器
 * 
 * @param scheduler 调度器实例
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_stop(timer_scheduler_t *scheduler)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    if (!s_task_ctx.running) {
        return TIMER_ERR_INVALID_STATE;
    }

    s_task_ctx.running = false;
    
    // 等待任务结束
    int retry = 0;
    while (eTaskGetState(s_task_ctx.task_handle) != eDeleted && retry < 10) {
        vTaskDelay(pdMS_TO_TICKS(100));
        retry++;
    }

    if (retry >= 10) {
        ESP_LOGW(TAG, "Scheduler task didn't stop gracefully");
    }

    s_task_ctx.task_handle = NULL;
    ESP_LOGI(TAG, "Scheduler stopped");
    return TIMER_OK;
}

/**
 * @brief 清理调度器资源
 * 
 * @param scheduler 调度器实例
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_deinit(timer_scheduler_t *scheduler)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    if (s_task_ctx.running) {
        ESP_LOGE(TAG, "Cannot deinit while scheduler is running");
        return TIMER_ERR_INVALID_STATE;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    // 释放定时器数组
    if (scheduler->timers) {
        free(scheduler->timers);
        scheduler->timers = NULL;
    }
    scheduler->timer_count = 0;
    scheduler->max_timers = 0;

    // 清理回调上下文
    memset(&scheduler->callback_ctx, 0, sizeof(timer_callback_ctx_t));

    // 删除互斥锁
    vSemaphoreDelete(s_task_ctx.mutex);
    s_task_ctx.mutex = NULL;

    ESP_LOGI(TAG, "Scheduler deinitialized");
    return ret;
}

/**
 * @brief 根据ID查找定时器索引
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @return int 找到返回索引，未找到返回-1
 */
static int find_timer_by_id(const timer_scheduler_t *scheduler, uint8_t timer_id)
{
    if (!scheduler || !scheduler->timers) {
        return -1;
    }

    for (int i = 0; i < scheduler->timer_count; i++) {
        if (scheduler->timers[i].id == timer_id) {
            return i;
        }
    }
    
    ESP_LOGW(TAG, "Timer %d not found", timer_id);
    return -1;
}

/**
 * @brief 删除指定的定时器
 * 
 * @param scheduler 调度器实例
 * @param timer_id 要删除的定时器ID
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_delete(timer_scheduler_t *scheduler, uint8_t timer_id)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, timer_id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    ESP_LOGI(TAG, "Deleting timer %d (type=%d, time=%02d:%02d:%02d)", 
             timer_id, scheduler->timers[index].type,
             scheduler->timers[index].time.hour,
             scheduler->timers[index].time.minute,
             scheduler->timers[index].time.second);

    // 移动后面的定时器前移
    if (index < scheduler->timer_count - 1) {
        memmove(&scheduler->timers[index], 
                &scheduler->timers[index + 1], 
                (scheduler->timer_count - index - 1) * sizeof(timer_config_t));
    }
    scheduler->timer_count--;

    // 保存更改
    ret = nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
    if (ret != TIMER_OK) {
        ESP_LOGE(TAG, "Failed to save timers after deletion: %d", ret);
    }

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 删除所有定时器
 * 
 * @param scheduler 调度器实例
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_delete_all(timer_scheduler_t *scheduler)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    ESP_LOGI(TAG, "Deleting all timers (count=%d)", scheduler->timer_count);

    // 清空定时器列表
    scheduler->timer_count = 0;

    // 保存空的定时器列表
    ret = nvs_storage.save_timers(scheduler->timers, 0);
    if (ret != TIMER_OK) {
        ESP_LOGE(TAG, "Failed to save empty timer list: %d", ret);
    }

    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 验证定时器配置
 * 
 * @param config 定时器配置
 * @return timer_err_t 操作结果
 */
static timer_err_t validate_timer_config(const timer_config_t *config)
{
    if (!config) {
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证时间范围
    if (config->time.hour >= 24 || 
        config->time.minute >= 60 || 
        config->time.second >= 60) {
        ESP_LOGE(TAG, "Invalid time values: %d:%d:%d", 
                 config->time.hour, config->time.minute, config->time.second);
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证时间段模式的结束时间
    if (config->type == TIMER_TYPE_PERIOD) {
        if (config->end_time.hour >= 24 || 
            config->end_time.minute >= 60 || 
            config->end_time.second >= 60) {
            ESP_LOGE(TAG, "Invalid end time values: %d:%d:%d",
                     config->end_time.hour, config->end_time.minute, config->end_time.second);
            return TIMER_ERR_INVALID_ARG;
        }
    }

    // 验证定时器类型
    if (config->type > TIMER_TYPE_PERIOD) {
        ESP_LOGE(TAG, "Invalid timer type: %d", config->type);
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证动作类型
    if (config->action > TIMER_ACTION_TOGGLE ||
        (config->type == TIMER_TYPE_PERIOD && config->end_action > TIMER_ACTION_TOGGLE)) {
        ESP_LOGE(TAG, "Invalid action type: %d", config->action);
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证周掩码(仅针对每周定时)
    if (config->type == TIMER_TYPE_WEEKLY && config->time.day_mask == 0) {
        ESP_LOGE(TAG, "Weekly timer has no days selected");
        return TIMER_ERR_INVALID_ARG;
    }
    
    // 注意：对于时间段定时器，day_mask = 0 表示每天都有效

    return TIMER_OK;
}

/**
 * @brief 生成唯一的定时器ID
 * 
 * 该函数通过以下步骤生成一个未被使用的定时器ID：
 * 1. 如果定时器列表为空，直接返回1作为第一个ID
 * 2. 否则，从1开始逐个检查每个数字是否已被使用
 * 3. 返回找到的第一个未使用的数字作为新ID
 * 4. 如果所有可用数字都已被使用，返回0表示分配失败
 * 
 * 例如：如果当前已有ID为1,2,4的定时器，则返回3作为新ID
 * 
 * @param scheduler 调度器实例
 * @return uint8_t 新的唯一ID（1-255），如果无法分配则返回0
 */
static uint8_t generate_unique_timer_id(const timer_scheduler_t *scheduler)
{
    // 如果没有定时器，返回1作为第一个ID
    if (scheduler->timer_count == 0) {
        return 1;
    }

    // 从1开始，找到第一个未被使用的数字
    for (uint8_t new_id = 1; new_id < UINT8_MAX; new_id++) {
        // 检查这个数字是否已被使用
        bool already_used = false;
        
        // 遍历所有现有定时器
        for (int i = 0; i < scheduler->timer_count; i++) {
            if (scheduler->timers[i].id == new_id) {
                already_used = true;  // 这个数字已经被使用了
                break;  // 不用继续检查其他定时器了
            }
        }
        
        // 如果这个数字还没被使用，就用它作为新ID
        if (!already_used) {
            ESP_LOGD(TAG, "Generated new timer ID: %d", new_id);
            return new_id;
        }
    }
    
    // 如果运行到这里，说明所有可用的数字都被使用了
    ESP_LOGE(TAG, "No available timer ID");
    return 0;
}

/**
 * @brief 添加定时器到调度器
 * 
 * @param scheduler 调度器实例
 * @param config 定时器配置
 * @param timer_id 返回的定时器ID
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_add(timer_scheduler_t *scheduler, const timer_config_t *config, uint8_t *timer_id)
{
    if (!scheduler || !config || !timer_id || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证配置
    timer_err_t err = validate_timer_config(config);
    if (err != TIMER_OK) {
        return err;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    if (scheduler->timer_count >= scheduler->max_timers) {
        ret = TIMER_ERR_FULL;
        goto exit;
    }

    // 生成新的定时器ID
    timer_config_t new_timer = *config;
    uint8_t new_id = generate_unique_timer_id(scheduler);
    if (new_id == 0) {
        ret = TIMER_ERR_NO_MEM;  // 使用NO_MEM表示ID资源耗尽
        goto exit;
    }
    new_timer.id = new_id;
    new_timer.last_trigger_time = 0;  // 初始化上次触发时间
    new_timer.in_period = false;

    // 添加定时器
    scheduler->timers[scheduler->timer_count] = new_timer;
    scheduler->timer_count++;
    *timer_id = new_timer.id;

    ESP_LOGI(TAG, "Added new timer: id=%d, type=%d, time=%02d:%02d:%02d", 
             new_timer.id, new_timer.type, 
             new_timer.time.hour, new_timer.time.minute, new_timer.time.second);

    // 保存更改
    ret = nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
    if (ret != TIMER_OK) {
        ESP_LOGE(TAG, "Failed to save new timer: %d", ret);
        scheduler->timer_count--;  // 回滚添加操作
    }

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 更新调度器中的定时器配置
 * 
 * @param scheduler 调度器实例
 * @param config 新的定时器配置
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_update(timer_scheduler_t *scheduler, const timer_config_t *config)
{
    if (!scheduler || !config || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    // 验证配置
    timer_err_t err = validate_timer_config(config);
    if (err != TIMER_OK) {
        return err;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, config->id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    // 备份旧配置(用于日志)
    timer_config_t old_config = scheduler->timers[index];

    // 更新配置
    scheduler->timers[index] = *config;

    ESP_LOGI(TAG, "Updated timer %d: type %d->%d, time %02d:%02d:%02d->%02d:%02d:%02d",
             config->id, old_config.type, config->type,
             old_config.time.hour, old_config.time.minute, old_config.time.second,
             config->time.hour, config->time.minute, config->time.second);

    // 保存更改
    ret = nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
    if (ret != TIMER_OK) {
        ESP_LOGE(TAG, "Failed to save timer updates: %d", ret);
        scheduler->timers[index] = old_config;  // 回滚更改
    }

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 设置定时器启用状态
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @param enable 是否启用
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_set_enabled(timer_scheduler_t *scheduler, uint8_t timer_id, bool enable)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, timer_id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    // 更新启用状态
    if (scheduler->timers[index].enabled != enable) {
        scheduler->timers[index].enabled = enable;
        
        // 保存更改
        ret = nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
        if (ret != TIMER_OK) {
            ESP_LOGE(TAG, "Failed to save timer state: %d", ret);
        }
    }

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 获取定时器列表
 * 
 * @param scheduler 调度器实例
 * @param timers 定时器配置数组
 * @param count 输入时表示数组大小，输出时表示实际定时器数量
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_get_list(timer_scheduler_t *scheduler, timer_config_t *timers, uint8_t *count)
{
    if (!scheduler || !timers || !count || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    if (*count < scheduler->timer_count) {
        ret = TIMER_ERR_INVALID_SIZE;
        goto exit;
    }

    // 复制定时器列表
    memcpy(timers, scheduler->timers, scheduler->timer_count * sizeof(timer_config_t));
    *count = scheduler->timer_count;

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 获取指定定时器的配置
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @param config 返回的定时器配置
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_get(timer_scheduler_t *scheduler, uint8_t timer_id, timer_config_t *config)
{
    if (!scheduler || !config || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, timer_id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    // 复制定时器配置
    *config = scheduler->timers[index];

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 获取定时器状态
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @param enabled 返回定时器是否启用
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_get_status(timer_scheduler_t *scheduler, uint8_t timer_id, bool *enabled)
{
    if (!scheduler || !enabled || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, timer_id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    *enabled = scheduler->timers[index].enabled;

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 获取调度器状态
 * 
 * @param scheduler 调度器实例
 * @param running 返回调度器是否正在运行
 * @param timer_count 返回当前定时器数量
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_get_scheduler_status(timer_scheduler_t *scheduler, bool *running, uint8_t *timer_count)
{
    if (!scheduler || !running || !timer_count || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    *running = s_task_ctx.running;
    *timer_count = scheduler->timer_count;

    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 暂停或恢复调度器
 * 
 * @param scheduler 调度器实例
 * @param pause true表示暂停，false表示恢复
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_pause_resume(timer_scheduler_t *scheduler, bool pause)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    if (!s_task_ctx.running || !s_task_ctx.task_handle) {
        ret = TIMER_ERR_INVALID_STATE;
        ESP_LOGW(TAG, "Scheduler is not running");
        goto exit;
    }

    if (s_task_ctx.paused == pause) {
        goto exit;  // 已经是目标状态
    }

    s_task_ctx.paused = pause;
    ESP_LOGI(TAG, "Scheduler %s", pause ? "paused" : "resumed");

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 重置定时器状态
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_reset(timer_scheduler_t *scheduler, uint8_t timer_id)
{
    if (!scheduler || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    int index = find_timer_by_id(scheduler, timer_id);
    if (index < 0) {
        ret = TIMER_ERR_NOT_FOUND;
        goto exit;
    }

    // 重置定时器状态
    timer_config_t *timer = &scheduler->timers[index];
    if (timer->type == TIMER_TYPE_ONCE) {
        timer->enabled = true;  // 重新启用单次定时器
        
        // 保存更改
        ret = nvs_storage.save_timers(scheduler->timers, scheduler->timer_count);
        if (ret != TIMER_OK) {
            ESP_LOGE(TAG, "Failed to save timer state after reset: %d", ret);
        }
    }

    ESP_LOGI(TAG, "Reset timer %d", timer_id);

exit:
    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

/**
 * @brief 检查定时器是否存在
 * 
 * @param scheduler 调度器实例
 * @param timer_id 定时器ID
 * @param exists 返回定时器是否存在
 * @return timer_err_t 操作结果
 */
timer_err_t timer_scheduler_exists(timer_scheduler_t *scheduler, uint8_t timer_id, bool *exists)
{
    if (!scheduler || !exists || !s_task_ctx.mutex) {
        return TIMER_ERR_INVALID_ARG;
    }

    timer_err_t ret = TIMER_OK;
    if (xSemaphoreTake(s_task_ctx.mutex, portMAX_DELAY) != pdTRUE) {
        return TIMER_ERR_TIMEOUT;
    }

    *exists = (find_timer_by_id(scheduler, timer_id) >= 0);

    xSemaphoreGive(s_task_ctx.mutex);
    return ret;
}

// 其他调度器函数实现... 